<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>vue学习</title>
  </head>

  <body>
    <!-- hhahah {{time}}
      <span>{{name}}</span>
      <span>{{person}}</span>
      <span>{{fullName}}</span> -->
    <!-- <my-button></my-button> -->
    <div id="app" a="kd" b="dkjf">
      <ul>
        <li>{{time}}</li>
      </ul>
    </div>
    <script src="./dist/vue.js"></script>
    <script>
      Vue.component("my-button", {
        template: "<button>hello</button>",
      });

      // let vm1 = new Vue({
      //   el: "#app",
      //   components: {
      //     "my-button": {
      //       template: "<button>world</button>",
      //     },
      //   },
      // });
    </script>
    <script>
      // Vue.options = {beforeCreate: [fn1, fn2]}
      Vue.mixin({
        beforeCreate() {
          console.log("before create 1");
        },
      });
      Vue.mixin({
        beforeCreate() {
          console.log("before create 2");
        },
      });
      Vue.mixin({
        beforeCreate() {
          console.log("before create 3");
        },
      });
    </script>
    <!-- 
  当在页面中直接写fullname时， fullname会去收集渲染watcher；
  firstName是在计算属性中使用， 所以他会收集计算属性watcher， 没有收集渲染watcher；
  fullname是没有dep的， 也就没有收集的功能
 -->
    <!-- 计算属性中的值应该记录， 计算属性watcher和rederwatcher -->
    <!-- Dep.target上赋值一个渲染watcher， 又将Dep.target设置为计算属性watcher -->
    <script>
      // viewModel  数据模型
      // 典型的MVVM： model  vm  view

      let vm = new Vue({
        el: "#app",
        components: {
          "my-button": {
            template: "<button>world</button>",
          },
        },
        // 开始生命周期函数
        beforeCreate() {
          console.log("before create");
        },
        created() {
          console.log("created");
        },
        beforeMount() {
          console.log("before mount");
        },
        mounted() {
          console.log("Mounted");
        },
        // 结束生命周期函数
        // 开始响应式原理
        data() {
          return {
            name: "zf",
            names: ["xiaoqi", "huha", "kkk"], // 用户很少通过索引操作数组 arr[82] = 1000;  Vue内部就想到对索引进行拦截，
            // 因为消耗严重， 内部数组不采用defineProperty
            // push、shift、pop、unshift、reverse、sort、splice 7个方法都是变异方法， 就是会
            // 更改源数据
            // 数组没有监控 索引的变化， 但是索引中对应的内容是对象类型时， 需要被监控==> 如果不被监控， 使用Object.freeze
            time: "20210924",
            person: {
              name: "seven",
              age: 22,
            },
            firstName: "zhang",
            lastName: "fang",
          };
          // return 111;
        },
        computed: {
          fullName: {
            // 方案1
            get() {
              // console.log("0000");
              return this.firstName + this.lastName;
            },
            set(newValue) {
              console.log(newValue);
            },
          },
        },
        watch: {
          name(newValue, oldValue) {
            console.log(newValue, oldValue);
          },
          "person.name"(newVal, oldVal) {
            console.log(newVal, oldVal);
          },
          time: [
            function a1(newval, old) {
              console.log(newval, old);
            },
            function a2(new1, old1) {
              console.log(new1, old1);
            },
          ],
          // time: ["aa", "bb"],
        },
        methods: {
          aa(newVal, oldVal) {
            console.log(newVal, oldVal);
          },
          bb(newVal, oldVal) {
            console.log(newVal, oldVal);
          },
        },
        // 结束响应式原理
      });

      console.log(vm.$options);
      setTimeout(() => {
        vm.time = "20211020";
      }, 1000);
      // setTimeout(() => {
      //   vm.name = "xiaoqi";
      //   vm.names.push("hhhh");
      //   vm.names.push({
      //     name: "kdjfkdj",
      //   });
      //   vm.name = "kkkk";
      //   vm.name = "vue111";
      //   vm.person.name = "kjdfkjdkfjkdfj";
      //   vm.time = "202109000";
      //   vm.$watch("name", function namehandler1() {
      //     console.log(arguments);
      //   });
      //   vm.lastName = "sang";
      //   // vm._update(vm._render()); // 重新调用render方法产生虚拟dom， 目前还没有diff
      // }, 1000);
    </script>
  </body>
</html>
<!-- 
  计算属性默认不执行 ==>  Object.defineProperty ==> getter
  多次取值如果依赖的值不变化， 就不会重新执行， vm.fullname = vm.fullname
  依赖的值变化， 需要重新执行 ： vm.firstname = "zhang",  fullname -- zhangfang

  dirty 表示这个值是不是脏的， true（取值后值变为false）， 依赖的值就变化了
  dirty ==> true
 -->
<!-- 
  Vue中嵌套层次不能太深， 否则会有大量的递归
  VUe中对象通过的是defineProperty实现的响应式， 拦截了get和set， 如果不存在的属性不会拦截， 也不会响应， 可以使用
  $set  ==> 让对象自己去notify(), 或者赋予一个新的对象
  Vue中数组改索引和长度， 是不会影响更新的， 通过变异方法可以更新视图（7个方法）数组中如果是对象类型， 
  修改对象也可以更新视图
  --->

<!-- 
    内部会将钩子函数 回调函数存到一个数组中， 当到达某个阶段后一次执行
   -->

<!-- 
     1. 给组件创建一个构造函数， 基于vue
     2. 开始生成虚拟节点， 对组件进行特殊处理 data.hook = {init(){}}
     3. 生成dom元素， 如果当前虚拟节点有hook.init属性， 说明是组件
     4. 对组件进行 new 组件().$mount() ==> vm.$el;
     5. 将组件的$el 插入到父容器中（父组件）
    -->
